﻿// -------------------------------------------------------------------------
//    @FileName         :    NFServicePackage.h
//    @Author           :    gaoyi
//    @Date             :    2025/1/2
//    @Email            :    445267987@qq.com
//    @Module           :    NFServicePackage
//
// -------------------------------------------------------------------------

// --- 文件总结 ---------------------------------------------------------------
// `NFServicePackage` 是背包服务类：
// - 提供背包相关的所有静态服务函数
// - 包括物品的增删改查、金钱操作、背包查询等
// - 作为外部调用背包功能的统一入口
// - 所有函数都是静态的，无需实例化
// ---------------------------------------------------------------------------

#pragma once

#include <NFLogicCommon/BagPage/NFBagPageOpDefine.h>

struct ItemOpData;
struct DelItemData;
class NFBagPageOp;
class NFBagPage;
class NFPlayer;
class WillAddItemData;

/**
 * @brief 背包服务类
 * 提供背包相关的所有静态服务函数，作为外部调用背包功能的统一入口
 */
class NFServicePackage
{
public:
    /**
     * 获取玩家的背包页面
     *
     * 此函数根据玩家和背包类型来获取特定的背包页面对象
     * 它用于管理玩家的不同类型的背包，例如主背包、装备背包等
     *
     * @param pPlayer 玩家对象指针，表示背包所属的玩家
     * @param iBagType 背包类型，用于区分不同的背包页面
     * @return NFBagPage* 返回背包页面对象指针，如果获取失败则返回nullptr
     */
    static NFBagPage* GetBagPage(NFPlayer* pPlayer, int iBagType);

    /**
     * 根据玩家和金钱类型获取金钱对象
     *
     * @param pPlayer 玩家指针，代表了游戏中的一个玩家实体
     * @param iMoneyType 金钱类型，用于指定需要获取的金钱种类
     * @return Money* 返回金钱对象指针，表示玩家拥有的指定类型的金钱
     */
    static Money* GetMoney(NFPlayer* pPlayer, int iMoneyType);

    /**
     * 获取玩家的金钱数量
     *
     * @param pPlayer 玩家对象指针，用于访问玩家的相关数据
     * @param iMoneyType 金钱类型，用于指定玩家拥有的不同类型金钱
     *
     * @return 玩家的金钱数量，以int64_t类型返回
     *
     * 此函数根据金钱类型参数，获取玩家对象中对应的金钱数量
     * 它通过玩家对象指针访问玩家数据，并根据金钱类型确定返回哪种金钱的数量
     */
    static int64_t GetMoneyNumber(NFPlayer* pPlayer, int iMoneyType);

    /**
     * 设置玩家的金钱数量
     *
     * @param pPlayer 玩家对象指针，用于识别特定的玩家
     * @param iMoneyType 金钱类型，用于指定玩家的哪一种金钱需要设置
     * @param llMoneyNum 金钱数量，要设置的金钱数值
     *
     * @return 返回整型值，表示方法执行的结果状态
     */
    static int SetMoneyNumber(NFPlayer* pPlayer, int iMoneyType, int64_t llMoneyNum);

public:
    /**
     * 向玩家背包中添加物品的函数
     *
     * @param pPlayer 玩家对象指针，用于访问玩家背包信息
     * @param enReason 添加物品的原因，用于记录物品添加的背景或情境
     * @param stWillAddItemData 待添加的物品数据，包含物品的详细信息
     * @param iNum 需要添加的物品数量
     * @param bAsPossible 是否尽可能地添加物品，默认为false。如果设为true，函数会尝试尽可能多地添加物品
     * @param pAddedNum 指向实际添加物品数量的指针，用于输出实际添加的物品数量，默认为NULL
     *
     * @return 返回添加物品的结果，0表示成功，非0表示失败
     *
     * 此函数尝试将指定数量的物品添加到玩家的背包中。如果bAsPossible设置为true，函数会尽量多添加物品，
     * 直到背包空间不足。如果pAddedNum不为NULL，它将记录实际添加的物品数量。
     */
    static int AddToBag(NFPlayer* pPlayer, int enReason, WillAddItemData& stWillAddItemData, int iNum, bool bAsPossible = false, int* pAddedNum = NULL);

    /**
     * 向玩家的背包中添加物品.
     *
     * 该函数尝试将指定数量的物品添加到玩家的背包中. 如果背包空间不足, 可以选择尽可能多地添加物品.
     *
     * @param pPlayer 必需参数, 指向玩家对象的指针.
     * @param enReason 必需参数, 表示添加物品的原因.
     * @param astWillAddItemData 必需参数, 包含将要添加的物品数据的向量.
     * @param aiWantAddNum 必需参数, 表示希望添加的每个物品的数量的向量.
     * @param bAsPossible 可选参数, 如果为true, 则尽可能多地添加物品, 即使不能添加全部数量. 默认值为false.
     * @param paiAddedNum 可选参数, 如果提供, 将填充实际添加的每个物品的数量. 默认为NULL.
     *
     * @return 返回添加物品的结果, 0表示成功, 非0表示失败.
     */
    static int AddToBag(NFPlayer* const pPlayer, int enReason, std::vector<WillAddItemData>& astWillAddItemData, std::vector<int>& aiWantAddNum, bool bAsPossible = false, std::vector<int>* paiAddedNum = NULL);

    /**
     * 向玩家的背包中添加物品页面。
     *
     * 此函数用于根据指定的条件和数量，将物品添加到玩家的背包中。
     * 它会考虑玩家的背包空间、物品的数量以及是否需要合并物品堆叠等因素。
     *
     * @param pPlayer 指向玩家对象的指针，表示哪个玩家的背包将添加物品。
     * @param enReason 物品添加的原因，用于记录物品是如何获得的。
     * @param stWillAddItemData 包含将要添加的物品数据的结构体，包括物品的属性等信息。
     * @param iNum 需要添加的物品的数量。
     * @param iBagType 背包的类型，可能有不同类型的背包（如普通背包、银行背包等）。
     * @param bAsPossible 是否尽可能地添加物品。如果为true，则尽可能多地添加物品，直到背包满或物品用完。
     * @param pAddedNum 指向一个整数的指针，用于接收实际添加的物品数量。这是一个可选参数。
     *
     * @return 返回添加物品的结果，可能是一个表示成功或失败的代码。
     */
    static int AddToBagPage(NFPlayer* pPlayer, int enReason, WillAddItemData& stWillAddItemData, int iNum, int iBagType, bool bAsPossible = false, int* pAddedNum = nullptr);

    /**
     * 向玩家的包裹中添加物品
     *
     * @param pPlayer 玩家对象指针，用于访问玩家包裹相关信息
     * @param vecItems 待添加的物品列表，包含多个Item对象
     * @param enPackageOpReason 包裹操作的原因，用于记录为何需要添加这些物品
     * @param bAsPossible 是否尽可能地添加物品，默认为false如果为true，将尽量根据玩家包裹的空间添加物品
     * @param pvecLeftItems 未被添加到包裹中的剩余物品列表，用于输出无法添加的物品信息可选参数，如果不需要此信息，可以不提供
     * @param bSyncToClient
     *
     * @return 成功添加到包裹中的物品数量如果返回-1，表示操作失败
     */
    static int AddItems(NFPlayer* pPlayer, const std::vector<Item>& vecItems, int enPackageOpReason, bool bAsPossible = false, std::vector<Item>* pvecLeftItems = nullptr, bool bSyncToClient = false);

    /**
     * 根据物品ID和数量为玩家增加物品
     *
     * @param pPlayer 玩家对象指针，表示为哪个玩家增加物品
     * @param enReason 增加物品的原因，用于记录物品增加的来源或原因
     * @param iItemID 物品ID，指定需要增加的物品类型
     * @param iNum 增加的物品数量，表示增加多少个指定物品
     * @param iBagType 背包类型，默认为0，用于指定物品增加到哪种类型的背包中
     * @param enBindType 物品绑定类型，默认为自动绑定，指定增加的物品是否绑定给玩家
     *
     * @return 返回增加物品的结果，通常用于表示增加是否成功
     */
    static int AddByItemIDAndNum(NFPlayer* pPlayer, int enReason, int iItemID, int iNum, int iBagType = 0, enItemBindType enBindType = EN_BT_AUTO);

    /**
     * 根据物品ID和数量添加物品到玩家的背包中
     *
     * @param pPlayer 玩家对象指针，表示哪个玩家将获得物品
     * @param astItemOne 物品列表，包含要添加的物品信息，每个物品的信息通过Item结构体给出
     * @param enReason 添加物品的原因，用于记录物品添加的日志或审计信息
     * @param bIsCommit 是否提交此次物品添加操作，true表示提交，false可能表示只做预演或查询
     * @param enBindType 物品绑定类型，默认为EN_BT_AUTO，表示自动绑定类型，这可能影响物品的使用或交易
     *
     * @return 返回操作结果，通常用于表示物品添加是否成功
     */
    static int AddItemsByItemIDAndNum(NFPlayer* pPlayer, const std::vector<Item>& astItemOne, int enReason, bool bIsCommit, enItemBindType enBindType = EN_BT_AUTO);

    /**
     * 为玩家添加物品
     *
     * @param pPlayer 玩家对象指针，表示要添加物品的玩家
     * @param enReason 添加物品的原因，用于记录物品变动的日志或审计
     * @param pItem 物品对象指针，表示要添加到玩家的物品
     * @param bCommit 是否提交更改的标志，默认为true，表示在添加物品后立即保存玩家的物品数据
     *
     * @return 返回添加物品操作的结果，0表示成功，非0表示失败
     *
     * 此函数用于在特定情况下为玩家添加物品，它可以用于游戏中的奖励分配、商店购买等情况
     * 它不仅处理物品的添加，还可以根据bCommit参数选择是否立即保存这些更改
     */
    static int AddByItem(NFPlayer* pPlayer, int enReason, NFGridItem* pItem, bool bCommit = true);

public:
    /**
     * 根据物品ID获取玩家背包中该物品的总数量
     *
     * @param pPlayer 玩家对象指针，用于访问玩家的背包信息
     * @param iItemID 物品ID，用于指定需要查询的物品
     * @param iTotalNum 输出参数，通过引用返回物品的总数量
     * @return 返回值为整型，表示操作的结果，0表示成功，非0表示失败
     *
     * 此函数通过玩家指针和物品ID来计算玩家背包中指定物品的总数
     * 它会遍历玩家的背包，匹配物品ID并累加数量，最终通过引用参数iTotalNum返回总数
     * 如果过程中出现错误，如玩家指针为空或物品ID无效，函数将返回非0值表示失败
     */
    static int GetAllItemTotalNum(NFPlayer* pPlayer, int iItemID, int& iTotalNum);

    /**
     * 获取玩家拥有指定物品的总数
     *
     * @param pPlayer 指向玩家对象的指针，代表要查询的玩家
     * @param iItemID 物品ID，用于指定要查询的物品类型
     * @param iTotalNum 引用参数，用于返回玩家拥有该物品的总数
     *
     * @return 返回值为整型，通常用于表示函数执行的状态码
     *         例如：0表示成功，非零值表示失败
     */
    static int GetItemTotalNum(NFPlayer* pPlayer, int iItemID, int& iTotalNum);
    static int GetItemTotalNum(NFPlayer* pPlayer, int iItemID);

    /**
     * 从玩家的背包中获取指定网格的物品信息
     *
     * @param pPlayer 玩家对象指针，用于访问玩家的背包信息
     * @param iBagType 背包类型，用于区分不同的背包（例如：主背包、装备背包等）
     * @param iGridIndex 背包网格索引，用于指定要获取物品信息的背包位置
     * @param pItemOut 输出参数，用于存储获取到的网格物品信息指针
     *
     * @return 返回操作结果：
     *         非0：表示操作失败，通常是因为参数无效或背包位置不存在
     *  0：表示操作成功，返回值可能用于表示物品的某种属性或状态
     *
     * 此函数主要用于游戏开发中，当需要从玩家的背包中获取特定位置的物品信息时调用
     * 它通过玩家指针、背包类型和网格索引来定位物品，并通过引用返回该物品的信息
     */
    static int GetItem(NFPlayer* pPlayer, int iBagType, int iGridIndex, NFGridItem* pItemOut);

    /**
     * 从玩家的指定背包中获取所有物品
     *
     * @param pPlayer 玩家对象指针，用于访问玩家的背包信息
     * @param iBagType 背包类型，用于指定要获取物品的背包
     * @param aWearList 输出参数，用于存储从背包中获取的物品列表
     * @return 返回获取的物品数量，-1表示获取失败
     */
    static int GetItem(NFPlayer* pPlayer, int iBagType, std::vector<NFGridItem>& aWearList);

    /**
     * 根据UUID从玩家的指定背包中获取单个物品
     *
     * @param pPlayer 玩家对象指针，用于访问玩家的背包信息
     * @param iBagType 背包类型，用于指定要获取物品的背包
     * @param ullUUID 物品的唯一标识符UUID，用于精确查找指定物品
     * @param pItemOut 输出参数，用于存储找到的物品信息如果未找到，则不修改该项
     * @return 找到物品返回0，否则返回-1表示未找到或获取失败
     */
    static int GetItemByUUID(NFPlayer* pPlayer, int iBagType, uint64_t ullUUID, NFGridItem* pItemOut);

    /**
     * 根据UUID从玩家的指定背包中获取单个物品
     *
     * @param pPlayer 玩家对象指针，用于访问玩家的背包信息
     * @param iBagType 背包类型，用于指定要获取物品的背包
     * @param ullUUID 物品的唯一标识符UUID，用于精确查找指定物品
     * @return 返回找到的物品指针，如果未找到则返回nullptr
     */
    static NFGridItem* GetItemByUUID(NFPlayer* pPlayer, int iBagType, uint64_t ullUUID);

    /**
     * 根据物品ID从玩家的指定背包中获取单个物品
     *
     * @param pPlayer 玩家对象指针，用于访问玩家的背包信息
     * @param iBagType 背包类型，用于指定要获取物品的背包
     * @param iItemID 物品ID，用于查找背包中匹配的物品
     * @param pItemOut 输出参数，用于存储找到的物品信息如果未找到，则不修改该项
     * @return 找到物品返回0，否则返回-1表示未找到或获取失败
     */
    static int GetItemByItemId(NFPlayer* pPlayer, int iBagType, int iItemID, NFGridItem* pItemOut);

    /**
     * 根据物品ID和UUID从玩家背包中获取物品
     *
     * 此函数用于在指定玩家的背包中查找具有特定物品ID和UUID的物品
     * 当需要精确查找某个具体物品时使用此函数，通过物品ID和UUID双重验证确保找到正确的物品
     *
     * @param pPlayer 玩家对象指针，用于访问该玩家的背包数据
     * @param iItemID 物品ID，用于指定要查找的物品类型
     * @param ullUUID 物品的唯一标识符，用于精确匹配特定的物品实例
     * @param pItemOut 输出参数，指向NFGridItem对象的指针，用于存储找到的物品信息
     *
     * @return 返回操作结果：
     *         - 0：成功找到物品并返回
     *         - -1：未找到匹配的物品或操作失败
     *
     * 注意：此函数会遍历玩家背包以查找匹配的物品，因此在性能敏感的场景中应谨慎使用
     */
    static int GetItemByItemIdAndUUID(NFPlayer* pPlayer, int iItemID, uint64_t ullUUID, NFGridItem* pItemOut);

    /**
     * 根据物品ID和UUID从玩家背包中获取物品指针
     *
     * 此函数用于在指定玩家的背包中查找具有特定物品ID和UUID的物品，并返回该物品的指针
     * 当需要直接访问某个具体物品时使用此函数，通过物品ID和UUID双重验证确保找到正确的物品实例
     *
     * @param pPlayer 玩家对象指针，用于访问该玩家的背包数据
     * @param iItemID 物品ID，用于指定要查找的物品类型
     * @param ullUUID 物品的唯一标识符，用于精确匹配特定的物品实例
     *
     * @return 返回找到的物品指针：
     *         - 非NULL：成功找到物品并返回指向该物品的指针
     *         - NULL：未找到匹配的物品或操作失败
     *
     * 注意：此函数会遍历玩家背包以查找匹配的物品，因此在性能敏感的场景中应谨慎使用
     * 使用者需要确保返回的指针在使用期间有效，避免悬空指针问题
     */
    static NFGridItem* GetItemByItemIdAndUUID(NFPlayer* pPlayer, int iItemID, uint64_t ullUUID);
public:
    /**
     * 删除玩家物品函数
     * @param pPlayer 玩家对象指针，用于访问玩家的物品信息
     * @param vecDelItemDatas 待删除的物品数据列表，包含要删除的物品信息
     * @param enPackageOpReason 物品删除的原因，用于记录物品变动的日志
     * @param bCompareResult 是否比较删除结果，默认为true，表示在删除后检查物品是否完全匹配
     * @return 返回删除操作的结果，通常用于表示操作是否成功
     */
    static int DelItems(NFPlayer* pPlayer, std::vector<DelItemData>& vecDelItemDatas, int enPackageOpReason, bool bCompareResult = true);

    /**
     * 根据物品ID和数量删除物品
     * @param pPlayer 玩家对象指针
     * @param enReason 删除物品的原因
     * @param iItemID 要删除的物品ID
     * @param iNum 要删除的物品数量
     * @param piDelNum 实际删除的物品数量指针，用于返回实际删除的数量，可选参数
     * @return 返回删除操作的结果
     */
    static int DelItemByItemIDAndNum(NFPlayer* pPlayer, int enReason, int iItemID, int iNum, int* piDelNum = nullptr);

    /**
     * 删除玩家背包中所有指定物品ID的物品
     * @param pPlayer 玩家对象指针
     * @param enReason 删除物品的原因
     * @param iItemID 要删除的物品ID
     * @param iBagType 背包类型，用于指定删除哪个背包中的物品，可选参数，默认为0
     * @return 返回删除操作的结果
     */
    static int DelAllItemByItemID(NFPlayer* pPlayer, int enReason, int iItemID, int iBagType = 0);

    /**
     * 根据格子位置和数量删除物品
     * @param pPlayer 玩家对象指针
     * @param enReason 删除物品的原因
     * @param iGridIndex 物品在背包中的格子位置
     * @param iNum 要删除的物品数量
     * @param iBagType 背包类型，可选参数，默认为0
     * @return 返回删除操作的结果
     */
    static int DelItemByNumWithGrid(NFPlayer* pPlayer, int enReason, int iGridIndex, int iNum, int iBagType = 0);

    /**
     * 根据格子位置删除物品
     * @param pPlayer 玩家对象指针
     * @param enReason 删除物品的原因
     * @param iGridIndex 物品在背包中的格子位置
     * @param iBagType 背包类型，可选参数，默认为0
     * @return 返回删除操作的结果
     */
    static int DelItemByGrid(NFPlayer* pPlayer, int enReason, int iGridIndex, int iBagType = 0);
public:
    static int OnVirtualMoneyInc(NFPlayer* pPlayer, int moneyType, int64_t value, int reason, int subReason);
public:
    static int CheckUseLimite(NFPlayer* pPlayer, int iItemId, int iNum);
    static int OnUse(NFPlayer* pPlayer, int iItemId, int iNum);
    static bool IsTempStorageHasItem(NFPlayer* pPlayer);
};
